package liming.tool.handle.net.udp.socket;
/**
 * Udp客户端实现，
 */

import liming.tool.handle.net.udp.base.UdpClient;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public abstract class UdpClientSocket extends UdpSocket implements UdpClient {
    private final DatagramSocket datagramSocket;
    private final HandleThread handleThread;
    private UdpReceiveMap udpReceiveMap;

    public UdpClientSocket(DatagramSocket datagramSocket, InetAddress inetAddress, int port) {
        super(inetAddress, port, 1);
        this.datagramSocket = datagramSocket;
        handleThread = new HandleThread();
    }

    public UdpClientSocket(int localPort, InetAddress inetAddress, int port) throws SocketException {
        this(new DatagramSocket(localPort), inetAddress, port);
    }

    public UdpClientSocket(InetAddress inetAddress, int port) throws SocketException {
        this(new DatagramSocket(), inetAddress, port);
    }

    @Override
    public boolean handleDataSubmissionPool(UdpReceiveMap udpReceiveMap, DatagramSocket datagramSocket) throws Exception {
        if (super.handleDataSubmissionPool(udpReceiveMap, datagramSocket)) {
            doWork(this.udpReceiveMap = udpReceiveMap);
            synchronized (this) {
                notifyAll();
            }
        }
        return false;
    }

    @Override
    public void close() throws IOException {
        handleThread.close();
    }

    @Override
    public UdpReceiveMap write(UdpReceiveMap udpReceiveMap) throws Exception {
        try {
            handleThread.start();
            send(datagramSocket, udpReceiveMap, inetAddress, port);
            return getUdpReceiveMap();
        } finally {
            close();
        }
    }

    @Override
    public UdpReceiveMap addReceiveMap(UdpReceiveMap udpReceiveMap) throws Exception {
        return null;
    }

    public synchronized UdpReceiveMap getUdpReceiveMap() throws InterruptedException {
        if (udpReceiveMap == null) wait();
        return udpReceiveMap;
    }

    private DatagramPacket getDatagramPacket() {
        return new DatagramPacket(new byte[SIZE], SIZE);
    }

    private class HandleThread extends Thread {
        private boolean run = false;

        @Override
        public void run() {
            run = true;
            String ip = datagramSocket.getLocalAddress() + ":" + datagramSocket.getLocalPort();
            while (run) {
                try {
                    DatagramPacket datagramPacket = getDatagramPacket();
                    datagramSocket.receive(datagramPacket);
                    put(datagramPacket, datagramSocket);
                } catch (SocketException ignored) {
                    writeStrongLog(ip + " 停止监听");
                } catch (IOException e) {
                    writeStrongLog(e);
                }
            }
        }

        public synchronized void close() {
            run = false;
            datagramSocket.close();
            notifyAll();
            interrupt();
        }
    }
}
